/**
 * Implementation for the CRC interface.
 *
 * @author Timothy Flynn (trflynn@wpi.edu)
 * @version April 11, 2012
 */
#include "crc.h"

// Generating polynomial
#define GX 0x1021

unsigned short updateCRC(unsigned short, unsigned short);
unsigned short augmentCRC(unsigned short);

/**
 * Given a message, calculate the CRC.
 */
unsigned short doCRC(char *msg) {
	unsigned short ch, i=0;
	unsigned short crc = 0xfff;

	while((ch = msg[i]) != 0) {
		crc = updateCRC(crc, ch);
		i++;
	}

	return augmentCRC(crc);
}

/**
 * Given a message and the old CRC, calculate the XOR new and old CRC.
 * If it is 0, then there are (likely) no errors.
 */
unsigned short undoCRC(char *msg, unsigned short crc) {
	return (doCRC(msg) ^ crc);
}

/**
 * Update a CRC for a byte of data.
 */
unsigned short updateCRC(unsigned short crc, unsigned short ch) {
	unsigned short i,v,xor_flag;
	v=0x80;
	for(i=0; i<8; i++) {
		if(crc & 0x8000) {
			xor_flag=1;
		} else {
			xor_flag=0;
		}
		crc = crc << 1;

		if(ch & v) {
			crc = crc ^ GX;
		}

		if(xor_flag) {
			crc = crc ^ GX;
		}
  
		v = v >> 1;
	}

	return crc;
}

/**
 * Make final adjustments to a CRC.
 */
unsigned short augmentCRC(unsigned short crc) {
	unsigned short i,xor_flag;

	for(i=0; i<16; i++) {
		if(crc & 0x8000) {
			xor_flag = 1;
		} else {
			xor_flag = 0;
		}

		crc = crc << 1;

		if(xor_flag) {
			crc = crc ^ GX;
		}
	}

	return crc;
}
